﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace DidaManager.Models.JsonConvert
{
    public class PortConfigToDownloadFile
    {
        [JsonPropertyName("PORTConfigs")]
        public List<PortConfigItem> PORTConfigs { get; set; } = new List<PortConfigItem>();

        public static PortConfigToDownloadFile ParseFromJson(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonString = File.ReadAllText(filePath);
            if (string.IsNullOrWhiteSpace(jsonString))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<PortConfigToDownloadFile>(jsonString, options) ?? new PortConfigToDownloadFile();
        }

        public static void SaveToJson(PortConfigToDownloadFile config, string filePath)
        {
            string jsonContent = JsonSerializer.Serialize(config, JsonSerializerOptionsManager.Compact);
            File.WriteAllText(filePath, jsonContent, new UTF8Encoding(false));
        }

        /// <summary>
        /// 从数据库JSON解析并转换为下载格式
        /// </summary>
        public static void ParseDbJsonAndSave(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonContent = File.ReadAllText(filePath);
            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var jsonArray = JArray.Parse(jsonContent);
            var dbPorts = new List<DatabasePortConfig>();

            foreach (JObject portJson in jsonArray)
            {
                var port = MapJsonToObject<DatabasePortConfig>(portJson);
                dbPorts.Add(port);
            }

            var downloadConfig = ConvertToDownloadFormat(dbPorts);
            SaveToJson(downloadConfig, filePath);
        }

        private static PortConfigToDownloadFile ConvertToDownloadFormat(List<DatabasePortConfig> dbPorts)
        {
            var result = new PortConfigToDownloadFile
            {
                PORTConfigs = new List<PortConfigItem>()
            };

            foreach (var dbPort in dbPorts)
            {
                if (dbPort.Extra == null) continue;

                var portType = GetPortType(dbPort.ActiveTab);
                var portConfig = new PortConfigItem
                {
                    Vaild = dbPort.Extra.Enable == 1,
                    PortName = dbPort.Name,
                    PortType = portType,
                    DeviceType = int.TryParse(dbPort.ProtoType, out int deviceType) ? deviceType : 0,
                };

                // 根据PortType决定使用PortParam还是NetParam
                if (portType == 1) // 串口
                {
                    portConfig.Param = new PortParam
                    {
                        COM = GetComPort(dbPort.Extra.Port),
                        BandRate = ToInt(dbPort.Extra.Baud, 9600),
                        Parity = dbPort.Extra.Parity,
                        DateBits = ToInt(dbPort.Extra.Bits, 8),
                        StopBit = ToInt(dbPort.Extra.Stop, 1),
                        ConvertPort = dbPort.Extra.Convert?.Port ?? 8080,
                        ConvertEnable = dbPort.Extra.Convert?.Enable ?? false,
                        
                        RespTimeOutMs = ToInt(dbPort.Extra.RespTimeOutMs, 3000),
                        SampleIntervalS = ToInt(dbPort.Extra.SampleIntervalS, 30),
                        FrameIntervalMs = ToInt(dbPort.Extra.FrameIntervalMs, 300),
                        Id = dbPort.Id,
                        Convert = new PortConvert
                        {
                            Com = dbPort.Extra.Convert?.Com ?? 0,
                            Port = dbPort.Extra.Convert?.Port ?? 0,
                            Enable = dbPort.Extra.Convert?.Enable ?? false
                        },
                        Opc = new PortOpc
                        {
                            LoginType = dbPort.Extra.Opc?.LoginType ?? string.Empty,
                            EndpointURL = dbPort.Extra.Opc?.EndpointURL ?? string.Empty,
                            UsrName = dbPort.Extra.Opc?.UsrName ?? string.Empty,
                            Password = dbPort.Extra.Opc?.Password ?? string.Empty,
                            Certificate = dbPort.Extra.Opc?.Certificate ?? string.Empty,
                            Key = dbPort.Extra.Opc?.Key ?? string.Empty
                        },
                        Remote = new PortRemote
                        {
                            Address = dbPort.Extra.Remote?.Address ?? string.Empty,
                            Port = dbPort.Extra.Remote?.Port ?? string.Empty,
                            ReportPackage = dbPort.Extra.Remote?.ReportPackage ?? string.Empty,
                            ReportHead = dbPort.Extra.Remote?.ReportHead ?? string.Empty,
                            ReportTail = dbPort.Extra.Remote?.ReportTail ?? string.Empty,
                            HeartTime = dbPort.Extra.Remote?.HeartTime ?? string.Empty
                        }
                    };
                }
                else if (portType == 2) // 网口
                {
                    portConfig.Param = new NetParam
                    {
                        PortNumber = ToInt(dbPort.Extra.IpPort, 502),
                        IP = dbPort.Extra.IpAddr ?? string.Empty,
                        RespTimeOutMs = ToInt(dbPort.Extra.RespTimeOutMs, 3000),
                        SampleIntervalS = ToInt(dbPort.Extra.SampleIntervalS, 30),
                        FrameIntervalMs = ToInt(dbPort.Extra.FrameIntervalMs, 300),
                        Id = dbPort.Id
                    };
                }
                else
                {
                    // 默认情况不使用任何参数
                    portConfig.Param = new { };
                }
                result.PORTConfigs.Add(portConfig);
            }

            return result;
        }

        private static int GetPortType(string activeTab)
        {
            int portType = 0;
            if (string.IsNullOrWhiteSpace(activeTab))
            {
                return portType;
            }
            switch(activeTab.ToLower())
            {
                case "ethernet":
                    portType = 2;
                    break;
                case "serial":
                    portType = 1;
                    break;
                default:
                    portType = 3; // 其他类型
                    break;
            }
            return portType;
        }

        private static int GetComPort(string portName)
        {
            if (string.IsNullOrWhiteSpace(portName)) return 1;
            
            // 从 "COM1" 提取数字
            var comStr = portName.ToUpper().Replace("COM", "").Trim();
            if (int.TryParse(comStr, out int comNum))
            {
                return comNum;
            }
            return 1;
        }

        private static int ToInt(string? value, int defaultValue)
        {
            if (int.TryParse(value, out int result))
            {
                return result;
            }
            return defaultValue;
        }

        private static T MapJsonToObject<T>(JObject json) where T : class, new()
        {
            var obj = new T();
            var properties = typeof(T).GetProperties();

            foreach (var prop in properties)
            {
                var jsonPropertyName = GetJsonPropertyName(prop);
                if (json.TryGetValue(jsonPropertyName, out JToken? value) && value != null)
                {
                    SetPropertyValue(obj, prop, value);
                }
            }

            return obj;
        }

        private static string GetJsonPropertyName(PropertyInfo prop)
        {
            var attr = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
            return attr?.Name ?? prop.Name;
        }

        private static void SetPropertyValue(object obj, PropertyInfo prop, JToken value)
        {
            if (obj == null) return;

            try
            {
                if (prop.PropertyType == typeof(string))
                {
                    prop.SetValue(obj, value.ToString());
                    return;
                }
                if (prop.PropertyType == typeof(int))
                {
                    prop.SetValue(obj, value.Type == JTokenType.Integer ? value.Value<int>() : ToInt(value.ToString(), 0));
                    return;
                }
                if (prop.PropertyType == typeof(bool))
                {
                    if (value.Type == JTokenType.Boolean)
                    {
                        prop.SetValue(obj, value.Value<bool>());
                    }
                    else
                    {
                        bool.TryParse(value.ToString(), out bool b);
                        prop.SetValue(obj, b);
                    }
                    return;
                }
                if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
                {
                    if (value is JObject nested)
                    {
                        var nestedObj = Activator.CreateInstance(prop.PropertyType);
                        if (nestedObj != null)
                        {
                            foreach (var nestedProp in prop.PropertyType.GetProperties())
                            {
                                var name = GetJsonPropertyName(nestedProp);
                                if (nested.TryGetValue(name, out var nv) && nv != null)
                                {
                                    SetPropertyValue(nestedObj, nestedProp, nv);
                                }
                            }
                            prop.SetValue(obj, nestedObj);
                        }
                    }
                }
            }
            catch
            {
                // ignore and leave default
            }
        }
    }

    public class PortConfigItem
    {
        [JsonPropertyName("Vaild")]
        public bool Vaild { get; set; }

        [JsonPropertyName("PortName")]
        public string PortName { get; set; } = string.Empty;

        [JsonPropertyName("PortType")]
        public int PortType { get; set; }

        [JsonPropertyName("DeviceType")]
        public int DeviceType { get; set; }

        [JsonPropertyName("Param")]
        public object Param { get; set; } = new object();
    }
    public class PortConvert
    {
        [JsonPropertyName("Com")]
        public int Com { get; set; }

        [JsonPropertyName("Port")]
        public int Port { get; set; }

        [JsonPropertyName("Enable")]
        public bool Enable { get; set; }
    }

    public class PortOpc
    {
        [JsonPropertyName("LoginType")]
        public string LoginType { get; set; } = string.Empty;

        [JsonPropertyName("EndpointURL")]
        public string EndpointURL { get; set; } = string.Empty;

        [JsonPropertyName("UsrName")]
        public string UsrName { get; set; } = string.Empty;

        [JsonPropertyName("Password")]
        public string Password { get; set; } = string.Empty;

        [JsonPropertyName("Certificate")]
        public string Certificate { get; set; } = string.Empty;

        [JsonPropertyName("Key")]
        public string Key { get; set; } = string.Empty;
    }

    public class PortRemote
    {
        [JsonPropertyName("Address")]
        public string Address { get; set; } = string.Empty;

        [JsonPropertyName("Port")]
        public string Port { get; set; } = string.Empty;

        [JsonPropertyName("ReportPackage")]
        public string ReportPackage { get; set; } = string.Empty;

        [JsonPropertyName("ReportHead")]
        public string ReportHead { get; set; } = string.Empty;

        [JsonPropertyName("ReportTail")]
        public string ReportTail { get; set; } = string.Empty;

        [JsonPropertyName("HeartTime")]
        public string HeartTime { get; set; } = string.Empty;
    }

    public class PortParam
    {
        [JsonPropertyName("COM")]
        public int COM { get; set; }

        [JsonPropertyName("BandRate")]
        public int BandRate { get; set; }

        [JsonPropertyName("Parity")]
        public string Parity { get; set; } = string.Empty;

        [JsonPropertyName("DateBits")]
        public int DateBits { get; set; }

        [JsonPropertyName("StopBit")]
        public int StopBit { get; set; }

        [JsonPropertyName("ConvertPort")]
        public int ConvertPort { get; set; }

        [JsonPropertyName("ConvertEnable")]
        public bool ConvertEnable { get; set; }

        [JsonPropertyName("RespTimeOutMs")]
        public int RespTimeOutMs { get; set; }

        [JsonPropertyName("SampleIntervalS")]
        public int SampleIntervalS { get; set; }

        [JsonPropertyName("FrameIntervalMs")]
        public int FrameIntervalMs { get; set; }

        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("Convert")]
        public PortConvert? Convert { get; set; }

        [JsonPropertyName("Opc")]
        public PortOpc? Opc { get; set; }

        [JsonPropertyName("Remote")]
        public PortRemote? Remote { get; set; }
    }

    public class NetParam
    {
        [JsonPropertyName("RespTimeOutMs")]
        public int RespTimeOutMs { get; set; }

        [JsonPropertyName("SampleIntervalS")]
        public int SampleIntervalS { get; set; }

        [JsonPropertyName("FrameIntervalMs")]
        public int FrameIntervalMs { get; set; }

        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("PortNumber")]
        public int PortNumber { get; set; } = 502;

        [JsonPropertyName("IP")]
        public string? IP { get; set; } = string.Empty;
    }
    // ========== 数据库JSON结构定义 ==========

    public class DatabasePortConfig
    {
        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("group_device_id")]
        public int GroupDeviceId { get; set; }

        [JsonPropertyName("name")]
        public string Name { get; set; } = string.Empty;

        [JsonPropertyName("proto_type")]
        public string ProtoType { get; set; } = string.Empty;

        [JsonPropertyName("activeTab")]
        public string ActiveTab { get; set; } = string.Empty;

        [JsonPropertyName("extra")]
        public DatabasePortExtra Extra { get; set; } = new DatabasePortExtra();
    }

    public class DatabasePortExtra
    {
        [JsonPropertyName("enable")]
        public int Enable { get; set; }

        [JsonPropertyName("type")]
        public string Type { get; set; } = string.Empty;

        [JsonPropertyName("device_type")]
        public string DeviceType { get; set; } = string.Empty;

        [JsonPropertyName("port")]
        public string Port { get; set; } = string.Empty;

        [JsonPropertyName("baud")]
        public string Baud { get; set; } = string.Empty;

        [JsonPropertyName("parity")]
        public string Parity { get; set; } = string.Empty;

        [JsonPropertyName("bits")]
        public string Bits { get; set; } = string.Empty;

        [JsonPropertyName("stop")]
        public string Stop { get; set; } = string.Empty;

        [JsonPropertyName("resp_time_out_ms")]
        public string RespTimeOutMs { get; set; } = string.Empty;

        [JsonPropertyName("sample_interval_s")]
        public string SampleIntervalS { get; set; } = string.Empty;

        [JsonPropertyName("frame_interval_ms")]
        public string FrameIntervalMs { get; set; } = string.Empty;

        [JsonPropertyName("ip_addr")]
        public string IpAddr { get; set; } = string.Empty;

        [JsonPropertyName("ip_port")]
        public string IpPort { get; set; } = string.Empty;

        [JsonPropertyName("convert")]
        public DatabasePortConvert? Convert { get; set; }

        [JsonPropertyName("opc")]
        public DatabasePortOpc? Opc { get; set; }

        [JsonPropertyName("remote")]
        public DatabasePortRemote? Remote { get; set; }
    }

    public class DatabasePortConvert
    {
        [JsonPropertyName("com")]
        public int Com { get; set; }

        [JsonPropertyName("port")]
        public int Port { get; set; }

        [JsonPropertyName("enable")]
        public bool Enable { get; set; }
    }

    public class DatabasePortOpc
    {
        [JsonPropertyName("loginType")]
        public string LoginType { get; set; } = string.Empty;

        [JsonPropertyName("endpointURL")]
        public string EndpointURL { get; set; } = string.Empty;

        [JsonPropertyName("usrName")]
        public string UsrName { get; set; } = string.Empty;

        [JsonPropertyName("password")]
        public string Password { get; set; } = string.Empty;

        [JsonPropertyName("certificate")]
        public string Certificate { get; set; } = string.Empty;

        [JsonPropertyName("key")]
        public string Key { get; set; } = string.Empty;
    }

    public class DatabasePortRemote
    {
        [JsonPropertyName("address")]
        public string Address { get; set; } = string.Empty;

        [JsonPropertyName("port")]
        public string Port { get; set; } = string.Empty;

        [JsonPropertyName("reportPackage")]
        public string ReportPackage { get; set; } = string.Empty;

        [JsonPropertyName("reportHead")]
        public string ReportHead { get; set; } = string.Empty;

        [JsonPropertyName("reportTail")]
        public string ReportTail { get; set; } = string.Empty;

        [JsonPropertyName("heartTime")]
        public string HeartTime { get; set; } = string.Empty;
    }
}
